package com.inwavetech.os.tests.sync.jsonparser;

import com.inwavetech.os.entity.Os;
import com.inwavetech.os.entity.enummap.EnumMap;
import com.inwavetech.os.entity.enummap.OsClosingStatusMap;
import com.inwavetech.os.entity.enummap.OsServiceOrderTypeMap;
import com.inwavetech.os.entity.enummap.OsStatusMap;
import com.inwavetech.os.entity.enummap.ProductDiagnosysMap;
import com.inwavetech.os.sync.jsonparser.InvalidEntityJsonException;
import com.inwavetech.os.sync.jsonparser.OsJsonParser;
import com.inwavetech.os.tests.sync.mock.OsJson;

import org.json.JSONException;
import org.json.JSONObject;

import java.math.BigDecimal;
import java.util.Date;
import java.util.concurrent.Callable;

/**
 * Created by jgskin on 3/5/14.
 */
public class OsJsonParserTest extends BaseJsonParserTest {

    private OsServiceOrderTypeMap serviceOrderTypeMap;
    private OsClosingStatusMap closingStatusMap;
    private OsStatusMap statusMap;

    @Override
    protected void setUp() throws Exception {
        statusMap = new OsStatusMap();
        closingStatusMap = new OsClosingStatusMap();
        serviceOrderTypeMap = new OsServiceOrderTypeMap();

        jsonParser = new OsJsonParser(statusMap, closingStatusMap, serviceOrderTypeMap, getDateHandler().getDateFormatter());

        anObject = new Os();

        aJson = new OsJson(1, statusMap, closingStatusMap, serviceOrderTypeMap, new ProductDiagnosysMap(), getDateHandler());
    }

    public void testInvalidJson_missingKeys() throws JSONException, InvalidEntityJsonException {
        parse();

        removeKeyAndTestException("id");
        removeKeyAndTestException("client");
        removeKeyAndTestException("store");
        removeKeyAndTestException("opener");
        removeKeyAndTestException("origin");
        removeKeyAndTestException("contact");
        removeKeyAndTestException("authorization");
        removeKeyAndTestException("activated_user");
        removeKeyAndTestException("finished_user");
        removeKeyAndTestException("assignment");
        removeKeyAndTestException("assignment_time");
        removeKeyAndTestException("roundup");
        removeKeyAndTestException("future_observation");
        removeKeyAndTestException("maintenance_observation");
        removeKeyAndTestException("finished_at");
        removeKeyAndTestException("service_justification");
        removeKeyAndTestException("travel_justification");
        removeKeyAndTestException("roundup");
        removeKeyAndTestException("future_observation");
        removeKeyAndTestException("name_responsible");
        removeKeyAndTestException("travel_price");
        removeKeyAndTestException("service_price");
        removeKeyAndTestException("service_order_type_id");
        removeKeyAndTestException("status_id");
        removeKeyAndTestException("closing_status_id");
        removeKeyAndTestException("created_at");
        removeKeyAndTestException("activated_at");
        removeKeyAndTestException("assignment_date");
    }

    public void testTravelPrice() throws Exception {
        assertBigDecimalEntry("travel_price", new Callable() {
            @Override
            public Object call() throws Exception {
                return ((Os) anObject).travel_price;
            }
        });
    }

    public void testServicePrice() throws Exception {
        assertBigDecimalEntry("service_price", new Callable() {
            @Override
            public Object call() throws Exception {
                return ((Os) anObject).service_price;
            }
        });
    }

    public void testServiceOrderTypeId() throws Exception {
        assertEnumEntry(
                "service_order_type_id",
                true,
                serviceOrderTypeMap,
                Os.ServiceOrderType.INSTALL,
                new Callable<Enum>() {
                    @Override
                    public Enum call() throws Exception {
                        return ((Os) anObject).service_order_type;
                    }
                }
        );
    }

    public void testClosingStatusId() throws Exception {
        assertEnumEntry(
                "closing_status_id",
                false,
                closingStatusMap,
                Os.ClosingStatus.CANCELED,
                new Callable<Enum>() {
                    @Override
                    public Enum call() throws Exception {
                        return ((Os) anObject).closing_status;
                    }
                }
        );
    }

    public void testStatusId() throws Exception {
        assertEnumEntry(
                "status_id",
                true,
                statusMap,
                Os.Status.ACTIVE,
                new Callable<Enum>() {
                    @Override
                    public Enum call() throws Exception {
                        return ((Os) anObject).status;
                    }
                }
        );
    }

    public void testCreatedAt() throws Exception {
        assertDateEntry("created_at", true, new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return ((Os) anObject).created_at;
            }
        });
    }

    public void testActivatedAt() throws Exception {
        assertDateEntry("activated_at", false, new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return ((Os) anObject).activated_date;
            }
        });
    }

    public void testAssignmentDate() throws Exception {
        assertDateEntry("assignment_date", false, new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return ((Os) anObject).assignment_date;
            }
        });
    }

    public void testUpdatedAt() throws Exception {
        assertDateEntry("updated_at", true, new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return ((Os) anObject).updated_at;
            }
        });
    }

    public void testFinishedAt() throws Exception {
        assertDateEntry("finished_at", false, new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return ((Os) anObject).finished_at;
            }
        });
    }

    public void testRemainingEntries() throws JSONException, InvalidEntityJsonException {
        parse();

        Os os = (Os) anObject;

        assertEquals(0, os.id);
        assertEquals(aJson.get("id"), os.original_id);
        assertEquals(aJson.get("client"), os.client);
        assertEquals(aJson.get("store"), os.store);
        assertEquals(aJson.get("opener"), os.opener);
        assertEquals(aJson.get("origin"), os.origin);
        assertEquals(aJson.get("contact"), os.contact);
        assertEquals(aJson.get("authorization"), os.authorization);
        assertEquals(aJson.get("activated_user"), os.activated_user);
        assertEquals(aJson.get("finished_user"), os.finished_user);
        assertEquals(aJson.get("assignment"), os.assignment);
        assertEquals(aJson.get("assignment_time"), os.assignment_time);
        assertEquals(aJson.get("roundup"), os.roundup);
        assertEquals(aJson.get("future_observation"), os.future_observation);
        assertEquals(aJson.get("maintenance_observation"), os.maintenance_observation);
        assertEquals(aJson.get("service_justification"), os.service_justification);
        assertEquals(aJson.get("travel_justification"), os.travel_justification);
        assertEquals(aJson.get("roundup"), os.roundup);
        assertEquals(aJson.get("future_observation"), os.future_observation);
        assertEquals(aJson.get("name_responsible"), os.name_responsible);
    }

    public void assertDateEntry(String keyName, boolean required, Callable<Date> getObjectDate) throws Exception {
        // test a valid date parsing
        assignAndParse(keyName, getDateHandler().getDateStr());
        assertEquals(getDateHandler().getDate(), getObjectDate.call());

        // test the a blank value
        assertBlankValue(keyName, required, getObjectDate);

        // test not valid values
        aJson.put(keyName, "nonvalid");
        assertInvalidEntityJsonException(keyName);

        aJson.put(keyName, "23/01/2014 20:00");
        assertInvalidEntityJsonException(keyName);
    }

    private void assertBigDecimalEntry(String keyName, Callable getObjectValue) throws Exception {
        // default valid values
        parse();

        // valid values
        // test double value
        assignAndParse(keyName, "1000589.89");
        // verify the parsed value
        assertEquals(new BigDecimal("1000589.89"), getObjectValue.call());

        assertValidBlankValue(keyName, getObjectValue);

        // not valid values
        aJson.put(keyName, "nonvalid");
        assertInvalidEntityJsonException(keyName);

        aJson.put(keyName, "nonnumeric");
        assertInvalidEntityJsonException(keyName);

        aJson.put(keyName, "12,50");
        assertInvalidEntityJsonException(keyName);
    }




}
